using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Text;

using System.IO;

using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;
using Athena.Core;

namespace Athena.Objects
{
    [Serializable()]
    public class CompartmentGlyph : ContainerGlyph
    {
        protected double _Volume = 1d;

        protected static bool FILLEDVIEW = true;

        public bool FilledView
        {
            get { return FILLEDVIEW; }
            set { FILLEDVIEW = value; }
        }

        public override object Clone()
        {
            return new CompartmentGlyph(this);
        }
        public CompartmentGlyph(CompartmentGlyph copy) : base(copy)
        {
            TextV = copy.TextV;
            TextH = copy.TextH;
            //the rest is the same as the normal constructor:            

            for (int i = 0; i < _Drawables.Count; ++i)
            {
                ((Compartment)_Item).AddItem(_Drawables[i].Item);   //very important -- add the items to the part                                

            }

            Location = copy._Location;
        }

        public override SizeF Dimensions
        {
            get
            {
                return base.Dimensions;
            }
            set
            {
                base.Dimensions = value;
                if (_Dimensions.Width < _dEdgeThickness * 2)
                    _dEdgeThickness = _Dimensions.Width / 4;
                if (_Dimensions.Height < _dEdgeThickness * 2)
                    _dEdgeThickness = _Dimensions.Height / 4;
            }
        }

        /// <summary>
        /// render the compartment
        /// </summary>
        /// <param name="g"></param>
        public override void RenderGlyph(Graphics g)
        {
            Pen oOutline = new Pen(_oEdgeColor, _dEdgeThickness);

            RectangleF oTemp = Bounds;

            Brush oFilled;
            if (_oFillColorStart == _oFillColorEnd || _Dimensions.Width < 2 || _Dimensions.Height < 2)
                oFilled = new SolidBrush(_oFillColorStart);
            else
                oFilled = new LinearGradientBrush(Location, new PointF(Location.X + Dimensions.Width, Location.Y + Dimensions.Height), _oFillColorStart, _oFillColorEnd);

            //Brush glow = new LinearGradientBrush(Center, new PointF(Location.X - 200, Location.Y - 200), Color.Red, Program.Model.Background.StartColor);
            Pen glow = new Pen(Color.OrangeRed, 5);
            GraphicsPath path = new GraphicsPath();

            switch (Shape)
            {
                case SHAPE.Box:
                    {
                        if (!FilledView)
                        {
                            path.AddRectangle(oTemp);
                            oTemp.Inflate(-2 * _dEdgeThickness, -2 * _dEdgeThickness);
                            path.AddRectangle(oTemp);
                            g.FillPath(oFilled, path);
                        }
                        else
                        {
                            g.FillRectangle(oFilled, Bounds);
                            oTemp.Inflate(-_dEdgeThickness, -_dEdgeThickness);
                            g.DrawRectangle(oOutline, oTemp.X, oTemp.Y, oTemp.Width, oTemp.Height);
                        }
                        if (_Glow)
                        {
                            oTemp.Inflate(2 * _dEdgeThickness, 2 * _dEdgeThickness);
                            g.DrawRectangle(glow, oTemp.X, oTemp.Y, oTemp.Width, oTemp.Height);
                        }
                        break;
                    }
                case SHAPE.Ellipse:
                    {
                        if (!FILLEDVIEW)
                        {
                            path.AddEllipse(oTemp);
                            oTemp.Inflate(-2 * _dEdgeThickness, -2 * _dEdgeThickness);
                            path.AddEllipse(oTemp);
                            g.FillPath(oFilled, path);

                        }
                        else
                        {
                            g.FillEllipse(oFilled, oTemp.X, oTemp.Y, oTemp.Width, oTemp.Height);
                            oTemp.Inflate(-_dEdgeThickness, -_dEdgeThickness);
                            g.DrawEllipse(oOutline, oTemp.X, oTemp.Y, oTemp.Width, oTemp.Height);
                        }
                                                
                        if (_Glow)
                        {
                            oTemp.Inflate(2 * _dEdgeThickness, 2 * _dEdgeThickness);
                            g.DrawEllipse(glow, oTemp.X, oTemp.Y, oTemp.Width, oTemp.Height);
                        }
                        break;
                    }
                case SHAPE.Octahedron:
                    {
                        float dOffset = Math.Min(Bounds.Width, Bounds.Height) * 0.10f;

                        GraphicsPath oPath = new GraphicsPath();

                        oPath.AddLine(oTemp.X, oTemp.Y + dOffset,
                                      oTemp.X + dOffset, oTemp.Y);
                        oPath.AddLine(oTemp.X + dOffset, oTemp.Y,
                                      oTemp.X + oTemp.Width - dOffset, oTemp.Y);
                        oPath.AddLine(oTemp.X + oTemp.Width - dOffset, oTemp.Y,
                                      oTemp.X + oTemp.Width, oTemp.Y + dOffset);
                        oPath.AddLine(oTemp.X + oTemp.Width, oTemp.Y + dOffset,
                                      oTemp.X + oTemp.Width, oTemp.Y + oTemp.Height - dOffset);
                        oPath.AddLine(oTemp.X + oTemp.Width, oTemp.Y + oTemp.Height - dOffset,
                                      oTemp.X + oTemp.Width - dOffset, oTemp.Y + oTemp.Height);
                        oPath.AddLine(oTemp.X + oTemp.Width - dOffset, oTemp.Y + oTemp.Height,
                                      oTemp.X + dOffset, oTemp.Y + oTemp.Height);
                        oPath.AddLine(oTemp.X + dOffset, oTemp.Y + oTemp.Height,
                                      oTemp.X, oTemp.Y + oTemp.Height - dOffset);
                        oPath.AddLine(oTemp.X, oTemp.Y + oTemp.Height - dOffset,
                                      oTemp.X, oTemp.Y + dOffset);

                        oPath.CloseFigure();
                        g.FillPath(oFilled, oPath);
                        g.DrawPath(oOutline, oPath);

                        if (_Glow)
                        {
                            GraphicsPath oPath2 = new GraphicsPath();

                            oPath2.AddLine(oTemp.X, oTemp.Y + dOffset,
                                          oTemp.X + dOffset, oTemp.Y);
                            oPath2.AddLine(oTemp.X + dOffset, oTemp.Y,
                                          oTemp.X + oTemp.Width - dOffset, oTemp.Y);
                            oPath2.AddLine(oTemp.X + oTemp.Width - dOffset, oTemp.Y,
                                          oTemp.X + oTemp.Width, oTemp.Y + dOffset);
                            oPath2.AddLine(oTemp.X + oTemp.Width, oTemp.Y + dOffset,
                                          oTemp.X + oTemp.Width, oTemp.Y + oTemp.Height - dOffset);
                            oPath2.AddLine(oTemp.X + oTemp.Width, oTemp.Y + oTemp.Height - dOffset,
                                          oTemp.X + oTemp.Width - dOffset, oTemp.Y + oTemp.Height);
                            oPath2.AddLine(oTemp.X + oTemp.Width - dOffset, oTemp.Y + oTemp.Height,
                                          oTemp.X + dOffset, oTemp.Y + oTemp.Height);
                            oPath2.AddLine(oTemp.X + dOffset, oTemp.Y + oTemp.Height,
                                          oTemp.X, oTemp.Y + oTemp.Height - dOffset);
                            oPath2.AddLine(oTemp.X, oTemp.Y + oTemp.Height - dOffset,
                                          oTemp.X, oTemp.Y + dOffset);

                            oPath2.CloseFigure();
                            //g.FillPath(oFilled, oPath2);
                            g.DrawPath(new Pen(Color.OrangeRed, 3), oPath2);
                        }

                        break;
                    }
                case SHAPE.RoundedRectangle:
                    {
                        GraphicsPath oPath = new GraphicsPath();

                        Utility.GenerateRoundedRectangle(oPath, oTemp);
                        RectangleF pathBounds = oPath.GetBounds();
                        Matrix oTransform = new Matrix();

                        oTransform.Scale(
                            oTemp.Width / pathBounds.Width,
                            oTemp.Height / pathBounds.Height, MatrixOrder.Prepend);
                        oTransform.Translate(oTemp.X - pathBounds.X * oTemp.Width / pathBounds.Width, oTemp.Y - pathBounds.Y * oTemp.Height / pathBounds.Height, MatrixOrder.Append);

                        oPath.Transform(oTransform);

                        path.AddPath(oPath, false);
                        if (!FILLEDVIEW)
                        {
                            oTemp.Inflate(-_dEdgeThickness, -_dEdgeThickness);

                            oPath = new GraphicsPath();
                            Utility.GenerateRoundedRectangle(oPath, oTemp);
                            pathBounds = oPath.GetBounds();
                            oTransform = new Matrix();
                            oTransform.Scale(
                                oTemp.Width / pathBounds.Width,
                                oTemp.Height / pathBounds.Height, MatrixOrder.Prepend);
                            oTransform.Translate(oTemp.X - pathBounds.X * oTemp.Width / pathBounds.Width, oTemp.Y - pathBounds.Y * oTemp.Height / pathBounds.Height, MatrixOrder.Append);

                            oPath.Transform(oTransform);
                            path.AddPath(oPath, false);
                            oPath.CloseFigure();
                        }


                        g.FillPath(oFilled, path);
                        if (FILLEDVIEW)
                        {
                            g.DrawPath(oOutline, path);
                        }

                        if (_Glow)
                        {
                            g.DrawPath(glow, oPath);
                        }

                        break;
                    }
            }

        }

        /// <summary>
        /// The complete constructor of a Compartment
        /// </summary>
        /// <param name="location"></param>
        public CompartmentGlyph(PointF location, SizeF dimension, List<IDrawable> nodes, List<Connector> edges, List<IDrawable> inputs, List<IDrawable> outputs)
        {
            SetDefaults();

            _Location = location;
            _Dimensions = dimension;
            Name = "compartment";
            
            _Drawables = nodes;

            Item =new Compartment("compartment", Text, nodes.Count + edges.Count, 1);
            //ItemPtr.Drawable = this;

            for (int i = 0; i < nodes.Count; ++i)
            {
                ((Compartment)_Item).AddItem((Node)nodes[i].Item);   //very important -- add the items to the part                                
            }
        }

        private void SetDefaults()
        {
            TextH = HorizontalAlignment.Center;
            TextV = VerticalAlignment.Bottom;
            Shape = SHAPE.RoundedRectangle;

            //_oFillColorStart = Color.Tomato;
            //_oFillColorEnd = Color.Maroon;
            //_oEdgeColor = Color.Black;

            _oEdgeColor = Color.Orange;
            _oFillColorStart = Color.NavajoWhite;
            _oFillColorEnd = Color.BlanchedAlmond;
            _dEdgeThickness = 7f;


            Item = new Compartment();
        }
        /// <summary>

        /// Initializes a new instance of the PartGlyph class.
        /// </summary>
        /// <param name="location"></param>
        public CompartmentGlyph(PointF location) : base(location)
        {
            SetDefaults();
        }

        public CompartmentGlyph() : base()
        {
            SetDefaults();
        }

        public override bool HasPreview
        {
            get { return true; }
        }

        /// <summary>
        /// checks if the point is situated on the border of this compartment
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public override bool Contains(PointF point)
        {
            RectangleF oTemp = Bounds;            
            oTemp.Inflate(-3 * _dEdgeThickness, -3 * _dEdgeThickness);
            if (oTemp.Contains(point))
            {
                return false;
            }
            else
            {
                oTemp.Inflate(6 * _dEdgeThickness, 6 * _dEdgeThickness);
                return oTemp.Contains(point);
            }
        }

        /// <summary>
        /// Checks that the given rectangle intersects with the border
        /// </summary>
        /// <param name="rect"></param>
        /// <returns></returns>
        public override bool IntersectsWith(RectangleF rect)
        {
            RectangleF oTemp = Bounds;            
            if (oTemp.Contains(rect))
            {
                return false;
            }
            else
            {                
                return oTemp.IntersectsWith(rect);
            }
        }

        public override void ShowToolTip(ToolTip tooltip, Control pnlCanvas, PointF location)
        {
            tooltip.ToolTipTitle = "Compartment: ";
            tooltip.SetToolTip(pnlCanvas,
                String.Format(
                            "{3}ID:\t{0}"
                          + "{3}Num. items:\t{1}"
                          + "{3}Volume:\t{2}",
                Name,
                _Drawables.Count,
                _Volume,
                "\r\n"));
        }
    }
}
